class Node {
    constructor(name = "_") {
        this._make_id(name);

        this.PCs = {
            '_': {
                'offer_pc': this._make_pc('_', true),
                'answer_pc': {},
            },
        };
    };

    _make_id = (name) => {
        // 生成随机id
        this.id = name + "-" + Math.random().toString(36).substr(2);
    };

    _make_pc(remote_id, proactive = true){
        const config = {
            iceServers: [{ urls: "stun:stun.ideasip.com" }],
        };
        const pc = new RTCPeerConnection(config);
        pc.remote_id = remote_id;
        pc.proactive = proactive;
        pc.temp_candidates = [];
        pc.candidates = [];

        if (pc.proactive) {
            pc.onnegotiationneeded = async (e) => {
                const offer = await e.target.createOffer()
                await e.target.setLocalDescription(offer);
                /*
                    此处更新key
                */
                log(`key 更新点(${e.target.remote_id}-offer_pc-createOffer)`);
                this._update_key(e.target);
                //    this._send_keys();
            };
        };

        pc.onicecandidate = (e) => {
            if (e.candidate) {
                e.target.temp_candidates.push(e.candidate)
            } else {
                e.target.candidates = e.target.temp_candidates;
                e.target.temp_candidates = [];
                /*
                    此处更新key
                */
                log(`key 更新点([${e.target.remote_id}] Onicecandidate)`);
                this._update_key(e.target);
            };
        };

        pc.addEventListener('connectionstatechange', (e) => {
            switch (e.target.connectionState) {
                case "connecting":
                    break;
                case 'connected':
                    log(`key 更新点(与[${e.target.remote_id}] Connected)`);
                    this._update_key(e.target);
                    break;
                case 'disconnected':
                    log(`key 更新点(与[${e.target.remote_id}] Disconnected)`);
                    this._update_key(e.target);
                    break;
                default:
                    log("收到未知状态:(" + e.target.connectionState + ")")
            }
        });

        return pc;
    };

    _send_one_key = (combined_key) => {

    };

    _close_one_target = (target_id) => {
        if (target_id in this.PCs) {
            for (let pc_type in this.PCs[target_id]) {
                if (this.PCs[target_id][pc_type].connectionState) {
                    this.PCs[target_id][pc_type].close();
                    log(`key 更新点(与[${target_id}] 关闭连接！)`);
                    this._update_key(this.PCs[target_id][pc_type]);
                    this.PCs[target_id][pc_type] = {};
                };
            };
        };
    };
    /* 首先，有小概率情况两个node之间同时互传了offer和answer，因此offer-pc和answer-pc需要同时存在，可以根据连接情况保存其一或全部保存，
    如果不分开存储，当需要关闭特定的remote node的已连接pc时，好像也没啥问题。
    */
    _update_key = (event_pc) => {

        let combined_key = {
            'state': event_pc.connectionState,
            'self_id': this.id,
            'target_id': event_pc.remote_id,
            'desc': event_pc.localDescription,
            'candis': event_pc.candidates,
        };
        this._send_one_key(combined_key);

    };

    _recive_one_key = async (remote_key) => {

        // 接收远程的key，以进行连接
        if (remote_key.target_id !== '_' && remote_key.target_id !== this.id) {
            log(`收到的远程key的目标Node(${remote_key.target_id})不是本Node(${this.id})，舍弃该key...`);
            return;
        };

        // if (remote_key.self_id in this.PCs) {
        //     log(`与收到的远程key的远程Node(ID:${remote_key.self_id})已经连接了!舍弃该key...`);
        //     return;
        // }
        if (!(remote_key.self_id in this.PCs)) {
            this.PCs[remote_key.self_id] = {
                'answer_pc': {},
                'offer_pc': {},
            };
        };

        switch (remote_key.desc.type) {
            case "offer":
                if (this.PCs[remote_key.self_id].answer_pc.connectionState == undefined) {
                    this.PCs[remote_key.self_id].answer_pc = this._make_pc(remote_key.self_id, false);
                } else if (this.PCs[remote_key.self_id].answer_pc.connectionState == 'connected') {
                    log(`与收到的远程key(offer)的远程Node(ID:${remote_key.self_id})的answer_pc已经连接了!舍弃该key...`);
                };

                await this.PCs[remote_key.self_id].answer_pc.setRemoteDescription(remote_key.desc);
                const answer = await this.PCs[remote_key.self_id].answer_pc.createAnswer();
                await this.PCs[remote_key.self_id].answer_pc.setLocalDescription(answer);
                log(`(${this.id} <==> ${remote_key.self_id})[answer_pc]offer description已处理，answer description已生成，请回复`);
                /*
                    此处更新key
                */
                log(`key 更新点([${remote_key.self_id}] 收到Offer，创建Answer)`);
                this._update_key(this.PCs[remote_key.self_id].answer_pc);
                // this._send_keys();

                for (const i in remote_key.candis) {

                    if (remote_key.candis[i]) {
                        await this.PCs[remote_key.self_id].answer_pc.addIceCandidate(remote_key.candis[i]);
                    };
                };
                log(`(${this.id} <==> ${remote_key.self_id})[answer_pc]远程candidates已加入`);
                break;

            case "answer":
                if (this.PCs[remote_key.self_id].offer_pc.connectionState == undefined) {
                    this.PCs[remote_key.self_id].offer_pc = this.PCs._.offer_pc;
                    this.PCs[remote_key.self_id].offer_pc.remote_id = remote_key.self_id;
                    this._update_key(this.PCs[remote_key.self_id].offer_pc);
                    this.PCs._.offer_pc = this._make_pc('_',true);
                } else if (this.PCs[remote_key.self_id].offer_pc.connectionState == 'connected') {
                    log(`与收到的远程key(offer)的远程Node(ID:${remote_key.self_id})的offer_pc已经连接了!舍弃该key...`);
                };

                await this.PCs[remote_key.self_id].offer_pc.setRemoteDescription(remote_key.desc);
                log(`(${this.id} <==> ${remote_key.self_id})[offer_pc]answer description已处理`);

                for (const i in remote_key.candis) {

                    if (remote_key.candis[i]) {
                        await this.PCs[remote_key.self_id].offer_pc.addIceCandidate(remote_key.candis[i]);
                    };
                };
                log(`(${this.id} <==> ${remote_key.self_id})[offer_pc]远程candidates已加入`);
                break;
        }

    };

    close = () => {
        // 断开所有连接，关闭自己
        for (let remote_id in this.PCs) {
            this._close_one_target(remote_id);
        };


        // this._clean_keys();

        this.PCs = {};

    };

};


class DataNode extends Node {
    constructor(name = "_") {
        super(name);
        this._make_pc_channel(this.PCs._.offer_pc);
        this._make_pc = (remote_id, proactive = true) => {
            let pc = super._make_pc(remote_id, proactive);
            this._make_pc_channel(pc);
            return pc;
        };
    };

    _make_pc_channel = (pc) => {
        if (pc.proactive) {
            pc.Channel = pc.createDataChannel("Channel");
            pc.Channel.onmessage = this.onMessage;
            pc.Channel.onopen = this.onopen;
            pc.Channel.onclose = this.onclose;
        }
        else {
            pc.ondatachannel = (event) => {
                event.target.Channel = event.channel;
                event.target.Channel.onmessage = this.onMessage;
                event.target.Channel.onopen = this.onopen;
                event.target.Channel.onclose = this.onclose;
            };
        };
    };

    onMessage = (e) => { };
    onopen = (e) => { };
    onclose = (e) => { };

    sendData = (data, target_id = '_') => {
        combined_data = {
            'self_id': this.id,
            'target_id': target_id,
            'content': data
        }
        if (target_id == '_') {
            for (let remote_id in this.PCs) {
                if (this.PCs[remote_id].offer_pc.connectionState == "connected") {
                    this.PCs[remote_id].offer_pc.Channel.send(JSON.stringify(combined_data));
                } else if (this.PCs[remote_id].answer_pc.connectionState == "connected") {
                    this.PCs[remote_id].answer_pc.Channel.send(JSON.stringify(combined_data));
                };
            };
        } else if (target_id in this.PCs) {
            if (this.PCs[target_id].offer_pc.connectionState == "connected") {
                this.PCs[target_id].offer_pc.Channel.send(JSON.stringify(combined_data));
            } else if (this.PCs[target_id].answer_pc.connectionState == "connected") {
                this.PCs[target_id].answer_pc.Channel.send(JSON.stringify(combined_data));
            } else {
                log(`发送目标：${target_id} 尚未连接成功!`);
            };
        } else {
            log(`发送目标：${target_id} 不存在!`);
        };
    };

    close() {
        for (let remote_id in this.PCs) {
            for (pc_type in this.PCs[remote_id]) {
                if (this.PCs[remote_id][pc_type].connectionState !== undefined) {
                    this.PCs[remote_id][pc_type].Channel.close();
                    this.PCs[remote_id][pc_type].Channel = null;
                };
            };
        };
        super.close();
    };
};

